package org.ns.framework.datasource.config;

import java.util.Map;
import java.util.function.Supplier;

import javax.sql.DataSource;

import org.ns.framework.datasource.redis.RedisConfig;
import org.ns.framework.datasource.redis.RedisSource;
import org.ns.framework.datasource.utils.DBSourceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class DataSourceLoader implements InitializingBean, ApplicationContextAware {

	private ApplicationContext applicationContext;
	@Autowired
	private DataSourceConfig dataSourceConfig;
	
	private static final Logger log = LoggerFactory.getLogger(DataSourceConfiguration.class);

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext;
		Map<String, Supplier<DataSource>> dataSources = dataSourceConfig.toDataSources();

		for (Map.Entry<String, Supplier<DataSource>> entry : dataSources.entrySet()) {
			String datasourceName = entry.getKey();
			Supplier<DataSource> dataSource = entry.getValue();

			if (registry.containsBeanDefinition(datasourceName)) {
				throw new RuntimeException("beanName 冲突：" + datasourceName + "[数据源名称与某Bean名称冲突、无法注册到IOC容器]");
			}

			BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DataSourceFactory.class)
					.addConstructorArgValue(DataSource.class).addConstructorArgValue(dataSource).setLazyInit(true)
					.getBeanDefinition();
			registry.registerBeanDefinition(datasourceName, beanDefinition);
		}

		for (Map.Entry<String, RedisConfig> entry : dataSourceConfig.getRedis().entrySet()) {
			String datasourceName = entry.getKey();
			datasourceName = DBSourceUtils.getSourceName(datasourceName, "redis"); // datasourceName.redis
			RedisConfig redis = entry.getValue();
			Supplier<RedisSource> redisSource = () -> new RedisSource(redis);

			if (registry.containsBeanDefinition(datasourceName)) {
				throw new RuntimeException("beanName 冲突：" + datasourceName + "[数据源名称与某Bean名称冲突、无法注册到IOC容器]");
			}
			log.info("加载 Redis 数据源配置: {}", datasourceName);
			BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(DataSourceFactory.class)
					.addConstructorArgValue(RedisSource.class).addConstructorArgValue(redisSource).setLazyInit(true)
					.getBeanDefinition();
			registry.registerBeanDefinition(datasourceName, beanDefinition);
		}
	}
}
